package cn.thens.kdroid.core.io

import java.lang.ref.WeakReference

import io.reactivex.Completable
import io.reactivex.Single

abstract class Ware<V> {
    abstract fun get(): Single<V>

    abstract fun put(value: V): Completable

    fun cache(cache: Ware<V>): Ware<V> {
        val source = this
        return object : Ware<V>() {
            override fun get(): Single<V> {
                val resume = source.get().doOnSuccess{ cache.put(it) }
                return cache.get().onErrorResumeNext(resume)
            }

            override fun put(value: V): Completable {
                return Completable.defer {
                    cache.put(value).subscribe()
                    source.put(value)
                }
            }
        }
    }

    fun <U> codec(codec: Codec<V, U>): Ware<U> {
        val source = this
        return object : Ware<U>() {
            override fun get(): Single<U> {
                return source.get().map { codec.encode(it) }
            }

            override fun put(value: U): Completable {
                return Completable.defer { source.put(codec.decode(value)) }
            }
        }
    }

    class NotFoundException : RuntimeException()

    companion object {

        fun <V> cache(): Ware<V> {
            return object : Ware<V>() {
                private var cache = WeakReference<V>(null)

                override fun get(): Single<V> {
                    return Single.create { emitter ->
                        val value = cache.get()
                        if (value != null) {
                            emitter.onSuccess(value)
                        } else {
                            emitter.onError(NotFoundException())
                        }
                    }
                }

                override fun put(value: V): Completable {
                    return Completable.create { emitter ->
                        cache = WeakReference(value)
                        emitter.onComplete()
                    }
                }
            }
        }
    }
}
